package com.asa.photopicker.photo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import com.asa.photopicker.LogUtils;

import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.media.ThumbnailUtils;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.ImageColumns;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.View;

public class Utils {
	private final static float ROUND_DIFFERENCE = 0.5f;
	public final static String KEY_MEDIAS = "medias";
	public final static String TAG = "Utils";
	private static BitmapLruCache sBitmapCache;

	public static BitmapLruCache getBitmapCache() {
		if (null == sBitmapCache) {
			long maxMemory = Runtime.getRuntime().maxMemory();
			sBitmapCache = new BitmapLruCache((int) (maxMemory / 8));
		}
		return sBitmapCache;
	}

	public static boolean isEmpty(List<?> list) {
		return null == list || list.isEmpty();
	}

	public static int dip2px(Context context, int dp) {
		return (int) (dp * context.getResources().getDisplayMetrics().density + ROUND_DIFFERENCE);
	}

	public static int px2dip(Context context, int px) {
		return (int) (px / context.getResources().getDisplayMetrics().density + ROUND_DIFFERENCE);
	}

	public static int getWidthPixels(Context context) {
		return context.getResources().getDisplayMetrics().widthPixels;
	}

	public final static int getSmallSize(Context context) {
		return getWidthPixels(context) / 5;
	}

	public final static int getDP(Context context, int dimen) {
		try {
			Resources resources = context.getResources();
			final float result = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dimen,
					resources.getDisplayMetrics());
			return (int) (result);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dimen;
	}

	/**
	 * get the width of child in gridview
	 * 
	 * @time Jan 13, 2014
	 * 
	 * @param numColums
	 *            numColums of GRIDVIEW
	 * @param spacing
	 *            Horizontal spacing of GRIDVIEW
	 * @param width
	 *            WIDTH of GRIDVIEW (padding left & padding right is not
	 *            included of GRIDVIEW)
	 * @return
	 */
	public final static int getAdapterItemSize(int numColums, int spacing, int width) {
		if (width < 0) {
			return 0;
		}
		if (numColums < 1 || spacing < 0) {
			return width;
		}
		int exSpace = (numColums + 1) * spacing;
		int trueWidth = width - exSpace;
		return (int) trueWidth / numColums;
	}

	public final static List<Folder> getImageFolders(Context context, String folderName) {
		ArrayList<Folder> folderList = new ArrayList<Folder>();
		HashMap<String, Folder> folderMap = new HashMap<String, Folder>();
		try {
			ContentResolver cr = context.getContentResolver();
			String[] imgProjection = { MediaStore.Video.Media.DATA };
			Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, imgProjection, null, null,
					MediaStore.Images.Media.DATE_ADDED + " DESC");
			resolveCursor(cursor, folderList, folderMap, folderName, false);
			if (cursor != null) {
				cursor.close();
			}
			folderMap.clear();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return folderList;
	}

	private final static void resolveCursor(Cursor cursor, ArrayList<Folder> folderList,
			HashMap<String, Folder> folderMap, String folderName, boolean isVideo) {
		if (cursor == null || cursor.getCount() <= 0) {
			LogUtils.d(TAG, "cursor is empty");
			return;
		}

		boolean hasNext = cursor.moveToFirst();
		while (hasNext) {
			int i = cursor.getColumnIndex(ImageColumns.DATA);
			// LogUtils.d(TAG, "resolveCursor ColumnIndex: %d", i);
			if (i != -1) {
				String path = cursor.getString(i);
				hasNext = cursor.moveToNext();
				File f = new File(path);
				// LogUtils.d(TAG, "resolveCursor ColumnIndex: %d, path: %s", i,
				// path);
				if (f.exists() && !isHide(path)) {
					String parent = f.getParent();

					String suffix = getSuffix(path);
					if (suffix == null) {
						continue;
					}
					if (!suffix.equals("jpg") && !suffix.equals("jpeg") && !suffix.equals("png")) {
						continue;
					}
					Folder allFolder = folderMap.get(folderName);
					Folder folder = folderMap.get(parent);
					if (allFolder == null) {
						allFolder = new Folder(folderName);
						folderMap.put(folderName, allFolder);
						folderList.add(allFolder);
					}
					if (folder == null) {
						folder = new Folder(parent);
						folderMap.put(parent, folder);
						folderList.add(folder);
					}
					allFolder.add(path);
					folder.add(path);
				}
			}
		}
	}

	public final static boolean isHide(String filePath) {
		File file = new File(filePath == null ? "" : filePath);
		if (!file.exists() || file.isHidden())
			return true;
		else if (file.getName().startsWith(".")) {
			return true;
		} else if (file.getParent() != null && !file.getParent().equals("") && file.getParent().equals("/"))
			return isHide(file.getParent());
		return false;
	}

	public final static String getSuffix(String filePath) {
		filePath = getFileName(filePath);
		if (TextUtils.isEmpty(filePath)) {
			return null;
		}
		try {
			int index = filePath.lastIndexOf(".");
			if (index < 0) {
				return null;
			}
			filePath = filePath.toLowerCase(Locale.ENGLISH);
			String suffix = filePath.substring(index + 1, filePath.length());
			return suffix;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public final static String getFileName(String filePath) {
		if (TextUtils.isEmpty(filePath)) {
			return null;
		}
		int index = filePath.lastIndexOf("/");
		if (index > 0) {
			filePath = filePath.substring(index + 1, filePath.length());
		}
		return filePath;
	}

	public static Bitmap getImageThumbnail(String absPath, int width, int height) {
		Bitmap bitmap = getBitmap(absPath, width, height, true);
		if (width > 0 && height > 0) {
			bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
		}
		return bitmap;
	}

	/**
	 * 根据宽高取图片
	 * 
	 * @param absPath
	 * @param width
	 * @param height
	 * @param isConstrainSize
	 *            是否等比例
	 * @return
	 */
	public static Bitmap getBitmap(String absPath, int width, int height, boolean equalRatio) {
		if (!exists(absPath)) {
			// LogUtils.e(TAG, "invalid parameters absPath " + absPath + " width
			// " + width + " height " + height);
			return null;
		}

		if (width <= 0 || height <= 0) {
			return BitmapFactory.decodeFile(absPath);
		}

		// LogUtils.d(TAG, "decode bitmap " + absPath + " width " + width + "
		// height " + height);
		Bitmap bitmap = null;
		Options options = getOptions(absPath);
		calcSizeOptions(options, width, height);
		// LogUtils.d(TAG, "decode bitmap inSampleSize=%d, %dx%d",
		// options.inSampleSize, options.outWidth, options.outHeight);
		try {
			bitmap = BitmapFactory.decodeFile(absPath, options);
		} catch (OutOfMemoryError error) {
			System.gc();
			try {
				bitmap = BitmapFactory.decodeFile(absPath, options);
			} catch (OutOfMemoryError er) {

			}
		}
		if (bitmap == null) {
			return null;
		}
		// LogUtils.d(TAG, "decode bitmap size=%dx%d", bitmap.getWidth(),
		// bitmap.getHeight());

		float ratioW = ((float) width) / bitmap.getWidth();
		float ratioH = ((float) height) / bitmap.getHeight();

		int rotate = getRotate(absPath);
		if (equalRatio) {
			ratioW = Math.min(ratioW, ratioH);
			ratioH = ratioW;
		}
		Matrix matrix = new Matrix();

		if (rotate > 0) {
			matrix.setRotate(rotate);
		}

		matrix.postScale(ratioW, ratioH);

		Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

		if (rotated == null) {
			return bitmap;
		}
		// LogUtils.d(TAG, "decode bitmap final=%d x %d", rotated.getWidth(),
		// rotated.getHeight());
		return rotated;
	}

	public static boolean exists(String filePath) {
		if (TextUtils.isEmpty(filePath)) {
			return false;
		}
		File file = new File(filePath);
		return file.exists();
	}

	public static Options getOptions(String filePath) {
		Options options = createDecodeBoundsOptions();
		BitmapFactory.decodeFile(filePath, options);
		return options;
	}

	/**
	 * 创建用于获取图片宽高的options
	 * 
	 * @return
	 */
	private static Options createDecodeBoundsOptions() {
		Options options = new Options();
		options.inPreferredConfig = Config.ALPHA_8;
		options.inJustDecodeBounds = true;
		return options;
	}

	/**
	 * 根据已取得的图片实际宽高计算缩放到目标宽高的缩放倍数
	 * 
	 * @param options
	 * @param desireWidth
	 * @param desireHeight
	 */
	private static void calcSizeOptions(Options options, int desireWidth, int desireHeight) {
		if (desireWidth <= 0 || desireHeight <= 0) {
			options.inSampleSize = 1;
		} else {
			options.inSampleSize = findBestSampleSize(options.outWidth, options.outHeight, desireWidth, desireHeight);
		}
		options.inJustDecodeBounds = false;
	}

	/**
	 * Returns the largest power-of-two divisor for use in downscaling a bitmap
	 * that will not result in the scaling past the desired dimensions.
	 * 
	 * @param actualWidth
	 *            Actual width of the bitmap
	 * @param actualHeight
	 *            Actual height of the bitmap
	 * @param desiredWidth
	 *            Desired width of the bitmap
	 * @param desiredHeight
	 *            Desired height of the bitmap
	 */
	static int findBestSampleSize(int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
		double wr = (double) actualWidth / desiredWidth;
		double hr = (double) actualHeight / desiredHeight;
		double ratio = Math.min(wr, hr);
		float n = 1.0f;
		while ((n * 2) <= ratio) {
			n *= 2;
		}

		return (int) n;
	}

	public static int getRotate(String absPath) {
		if (!exists(absPath)) {
			// LogUtils.e(TAG, "invalid file path");
			return 0;
		}

		ExifInterface exifInterface = null;
		try {
			exifInterface = new ExifInterface(absPath);
		} catch (IOException e) {
			e.printStackTrace();
			return 0;
		}

		int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
				ExifInterface.ORIENTATION_UNDEFINED);
		int rotate = 0;
		switch (orientation) {
		case ExifInterface.ORIENTATION_ROTATE_90:
			rotate = 90;
			break;
		case ExifInterface.ORIENTATION_ROTATE_180:
			rotate = 180;
			break;
		case ExifInterface.ORIENTATION_ROTATE_270:
			rotate = 270;
			break;
		default:
			break;
		}
		// LogUtils.e(TAG, "image rotate " + rotate);
		return rotate;
	}

	/**
	 * 设置view的visibile属性, 先判断是否一致
	 * 
	 * @param view
	 * @param visible
	 */
	public static void setVisibility(View view, int visible) {
		if (view != null && view.getVisibility() != visible) {
			view.setVisibility(visible);
		}
	}

}
